#include <linux/init.h>              //初始化头文件
#include <linux/module.h>            //最基本的文件，支持动态添加和卸载模块。
#include <linux/miscdevice.h>        //注册杂项设备头文件
#include <linux/fs.h>                //注册设备节点的文件结构体
#include <linux/kdev_t.h>
#include <linux/uaccess.h>

/**
 * 
 *  杂项设备使用
* 测试：
root@SOM-RK3399v2:/drv_code# insmod  miscdevice.ko 
crw------- 1 root root 10, 54 Oct 16 10:53 /dev/test
*
*
*/

static int test_chrdev_open(struct inode *inode, struct file *file)
{
	// 应用层调用open 函数 
  	printk(KERN_INFO "test_chrdev_open  \n");
  	return 0; 
};



static int test_chrdev_release( struct inode *inode, struct file *file )
{
    printk(KERN_INFO "test_chrdev_release \n");

	  return 0;
};

//把数据从内核空间拷贝到用户空间
char kbuf[100]={0}; 
static ssize_t test_chrdev_read( struct file *file,char __user *ubuf, size_t len,loff_t *offset )
{
    int ret = -1;
    printk(KERN_INFO "test_chrdev_read \n");
    ret =  copy_to_user(ubuf,kbuf,len);
    if(ret){
    	 printk(KERN_INFO "copy_to_user fail =%d \n" ,ret);
    	 return -EINVAL;
    }
     printk(KERN_INFO "copy_to_user suc  =%d \n" ,ret);
    return 0;
}


static ssize_t test_chrdev_write( struct file *file,const char __user *ubuf ,size_t len,loff_t *offset )
{
    int ret = -1;
    printk(KERN_INFO "test_chrdev_write \n");
   
    
    memset(kbuf,0,sizeof(kbuf));

     // 如果复制成功那么返回0， 如果不成功复制则返回尚未复制成功复制剩下的字节数
    ret= copy_from_user(kbuf,ubuf,len);
    if(ret){
    	 printk(KERN_INFO "copy_from_user fail =%d \n" ,ret);
    	 return -EINVAL;
    }
    printk(KERN_INFO "copy_from_user suc: %s",kbuf);

    return 0;
}



/* File operations struct for character device */
// 驱动名字 _fops  
// 这4个函数，通过应用来调用
static const struct file_operations test_fops = {
	.owner		= THIS_MODULE,     //惯例 , 默认
	.open		= test_chrdev_open,  // 将来应用open打开这个设备是实际调用的函数 
	.release	= test_chrdev_release,  // 
	.write      = test_chrdev_write,
	.read       = test_chrdev_read, 
};


struct miscdevice misc_dev = {       //杂项设备结构体
    
    .minor = MISC_DYNAMIC_MINOR,     //这个宏表示杂项设备次设备号自动分配
    .name = "test",                  //杂项设备名字是test 
    .fops = &test_fops,              //文件操作集

};
static int __init misc_init(void)           
{ 
    int ret;
    ret = misc_register(&misc_dev); //在初始化函数中注册杂项设备
    if (ret < 0)
    {
        printk("misc registe is error \n"); //打印注册杂项设备失败
    }
    printk("misc registe is succeed \n");//打印注册杂项设备成功
    return 0;
}
static void __exit misc_exit(void)
{ 

    misc_deregister(&misc_dev);     //在卸载函数中注销杂项设备
    printk(" misc goodbye! \n");
}
module_init(misc_init);
module_exit(misc_exit);
MODULE_LICENSE("GPL");
